package douyin

import (
	"crypto/md5"
	"encoding/json"
	"fmt"
	"github.com/zeromicro/go-zero/core/logx"
	"io"
	"reflect"
	"sort"
	"strings"
	"xialou_platform/app/tools"
)

type PayReq struct {
	AppId       string `json:"app_id"`
	OutOrderNo  string `json:"out_order_no"`
	TotalAmount int64  `json:"total_amount"`
	Subject     string `json:"subject"`
	Body        string `json:"body"`
	ValidTime   int    `json:"valid_time"`
	Sign        string `json:"sign"`
	CpExtra     string `json:"cp_extra,omitempty"`
	NotifyUrl   string `json:"notify_url"`
}
type PayResp struct {
	ErrNo   int    `json:"err_no"`
	ErrTips string `json:"err_tips"`
	Data    struct {
		OrderId    string `json:"order_id"`
		OrderToken string `json:"order_token"`
	} `json:"data"`
}

const salt = "cr5Ke9ycsv8N0vgRZ4sudv6JeqCKwsg4UGyCeo4s"

func (c *DouYinClient) CreatePay(req *PayReq) (*PayResp, error) {
	req.AppId = c.conf.AppId
	req.Sign = requestSign(req)
	resp, err := tools.Post(CreateOrderUrl, req)
	if err != nil {
		logx.Errorf("err:%+v", err)
		return nil, err
	}
	var data PayResp
	all, err := io.ReadAll(resp.Body)
	err = json.Unmarshal(all, &data)
	if err != nil {
		logx.Errorf("err:%+v", err)
		return nil, err
	}
	return &data, nil
}

type QueryOrderReq struct {
	AppId      string `json:"app_id"`
	OutOrderNo string `json:"out_order_no"`
	Sign       string `json:"sign"`
}

type QueryOrderResp struct {
	ErrNo       int    `json:"err_no"`
	ErrTips     string `json:"err_tips"`
	OutOrderNo  string `json:"out_order_no"`
	OrderId     string `json:"order_id"`
	PaymentInfo struct {
		TotalFee         int    `json:"total_fee"`
		OrderStatus      string `json:"order_status"`
		PayTime          string `json:"pay_time"`
		Way              int    `json:"way"`
		ChannelNo        string `json:"channel_no"`
		ChannelGatewayNo string `json:"channel_gateway_no"`
		SellerUid        string `json:"seller_uid"`
		ItemId           string `json:"item_id"`
		CpsInfo          string `json:"cps_info"`
	} `json:"payment_info"`
}

func (c *DouYinClient) QueryOrder(req *QueryOrderReq) (*QueryOrderResp, error) {
	resp, err := tools.Post(QueryOrderUrl, req)
	if err != nil {
		logx.Errorf("err:%+v", err)
		return nil, err
	}
	var data QueryOrderResp
	all, err := io.ReadAll(resp.Body)
	err = json.Unmarshal(all, &data)
	if err != nil {
		logx.Errorf("err:%+v", err)
		return nil, err
	}
	return &data, nil
}

// CreateRefundReq 订单退款参数
type CreateRefundReq struct {
	AppId        string `json:"app_id"`
	OutOrderNo   string `json:"out_order_no"`
	OutRefundNo  string `json:"out_refund_no"`
	Reason       string `json:"reason"`
	RefundAmount int    `json:"refund_amount"`
	Sign         string `json:"sign"`
	CpExtra      string `json:"cp_extra"`
	NotifyUrl    string `json:"notify_url"`
}

type CreateRefundResp struct {
	ErrNo    int    `json:"err_no"`
	ErrTips  string `json:"err_tips"`
	RefundNo string `json:"refund_no"`
}

func (c *DouYinClient) CreateRefund(req *CreateRefundReq) (*CreateRefundResp, error) {
	req.AppId = c.conf.AppId
	req.Sign = requestSign(req)
	resp, err := tools.Post(CreateRefundUrl, req)
	if err != nil {
		logx.Errorf("err:%+v", err)
		return nil, err
	}
	var data CreateRefundResp
	all, err := io.ReadAll(resp.Body)
	err = json.Unmarshal(all, &data)
	if err != nil {
		logx.Errorf("err:%+v", err)
		return nil, err
	}
	return &data, nil
}

func structToMap(item interface{}) map[string]interface{} {

	res := map[string]interface{}{}
	if item == nil {
		return res
	}
	v := reflect.TypeOf(item)
	reflectValue := reflect.ValueOf(item)
	reflectValue = reflect.Indirect(reflectValue)

	if v.Kind() == reflect.Ptr {
		v = v.Elem()
	}
	for i := 0; i < v.NumField(); i++ {
		tag := v.Field(i).Tag.Get("json")
		field := reflectValue.Field(i).Interface()
		if tag != "" && tag != "-" {
			if v.Field(i).Type.Kind() == reflect.Struct {
				res[tag] = structToMap(field)
			} else {
				res[tag] = field
			}
		}
	}
	return res
}

func requestSign(req interface{}) string {
	paramsMap := structToMap(req)
	var paramsArr []string
	for k, v := range paramsMap {
		if k == "other_settle_params" || k == "app_id" || k == "thirdparty_id" || k == "sign" {
			continue
		}
		value := strings.TrimSpace(fmt.Sprintf("%v", v))
		if strings.HasPrefix(value, "\"") && strings.HasSuffix(value, "\"") && len(value) > 1 {
			value = value[1 : len(value)-1]
		}
		value = strings.TrimSpace(value)
		if value == "" || value == "null" {
			continue
		}
		paramsArr = append(paramsArr, value)
	}

	paramsArr = append(paramsArr, salt)
	sort.Strings(paramsArr)
	return fmt.Sprintf("%x", md5.Sum([]byte(strings.Join(paramsArr, "&"))))
}
